package com.talent.service.iot.mqtt.codec;

import com.talent.service.iot.mqtt.codec.decoder.*;
import com.talent.service.iot.mqtt.config.Constant;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.mqtt.MqttMessageType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;

/**
 * @ClassName：MessageCodec
 * @Author: hszhou
 * @Date: 2024/11/15 16:16
 * @Description: mtt的解码器
 */
public class TlMqttMessageCodec extends ByteToMessageDecoder {

    private static final  Logger logger = LoggerFactory.getLogger(TlMqttMessageCodec.class);

    private final TlMqttConnectDecoder connectDecoder;

    private final TlMqttDisConnectDecoder disConnectDecoder;

    private final TlMqttHeartBeatDecoder heartBeatDecoder;

    private final TlMqttPubAckDecoder pubAckDecoder;

    private final TlMqttPubCompDecoder pubCompDecoder;

    private final TlMqttPublishDecoder publishDecoder;

    private final TlMqttPubRecDecoder pubRecDecoder;

    private final TlMqttPubRelDecoder pubRelDecoder;

    private final TlMqttSubscribeDecoder subscribeDecoder;

    private final TlMqttUnSubscribeDecoder unSubscribeDecoder;

    public TlMqttMessageCodec(TlMqttConnectDecoder connectDecoder, TlMqttDisConnectDecoder disConnectDecoder, TlMqttHeartBeatDecoder heartBeatDecoder, TlMqttPubAckDecoder pubAckDecoder, TlMqttPubCompDecoder pubCompDecoder, TlMqttPublishDecoder publishDecoder, TlMqttPubRecDecoder pubRecDecoder, TlMqttPubRelDecoder pubRelDecoder, TlMqttSubscribeDecoder subscribeDecoder, TlMqttUnSubscribeDecoder unSubscribeDecoder) {
        this.connectDecoder = connectDecoder;
        this.disConnectDecoder = disConnectDecoder;
        this.heartBeatDecoder = heartBeatDecoder;
        this.pubAckDecoder = pubAckDecoder;
        this.pubCompDecoder = pubCompDecoder;
        this.publishDecoder = publishDecoder;
        this.pubRecDecoder = pubRecDecoder;
        this.pubRelDecoder = pubRelDecoder;
        this.subscribeDecoder = subscribeDecoder;
        this.unSubscribeDecoder = unSubscribeDecoder;
    }


    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception {


        //如果刻度字节小于2个字节 说明还没有读取到正确的包 因为固定头最少为2个字节
        if(in.readableBytes()<2){
            return;
        }

        //标记一下 后面读取的时候 如果没有读取到正确的值的时候 就可以回到原来的位置 重新涂
        in.markReaderIndex();

        //读取第一个字节 包含消息类型和标志位信息
        short type = in.readUnsignedByte();
        int remainingLength = decodeRemainingLength(in);
       // logger.info("可读字节【{}】--数据长度【{}】",in.readableBytes(),remainingLength);
        //检查是否接收到了完整的数据包
        if (in.readableBytes() < remainingLength) {
            //如果数据不够 回滚读索引到之前标记的位置 等待更多数据到来
            in.resetReaderIndex();
            return;
        }
        //完整的数据已经接收 读取并解析整个Mqtt的数据包
        ByteBuf messageBuf = in.readBytes(remainingLength);
        int messageType = type >> Constant.MESSAGE_BIT;
        MqttMessageType MESSAGE_TYPE = MqttMessageType.valueOf(messageType);
    //   logger.info("收到消息类型【{}】-【{}】",messageType,MESSAGE_TYPE);
    //    TlLog.logger("收到消息的16进制数据",in);
        Object req=null;
        switch (MESSAGE_TYPE){
            case CONNECT:
                req = connectDecoder.build(messageBuf, remainingLength);
                break;
            case DISCONNECT:
                req= disConnectDecoder.build(remainingLength);
                break;
            case PUBLISH:
                req =publishDecoder.build(messageBuf,type,remainingLength);
                break;
            case PUBACK:
                req = pubAckDecoder.build(messageBuf,remainingLength);
                break;
            case PUBREC:
                req = pubRecDecoder.build(messageBuf,remainingLength);
                break;
            case PUBREL:
                req = pubRelDecoder.build(messageBuf,remainingLength);
                break;
            case PUBCOMP:
                req = pubCompDecoder.build(messageBuf,remainingLength);
                break;
            case SUBSCRIBE:
                req = subscribeDecoder.build(messageBuf,remainingLength);
                break;
            case UNSUBSCRIBE:
                req = unSubscribeDecoder.build(messageBuf,remainingLength);
                break;
            case PINGREQ:
                req = heartBeatDecoder.build(remainingLength);
                break;
            default:
                throw new IllegalArgumentException("unknown message type: " + MESSAGE_TYPE);
        }

        out.add(req);
    }







//    private int decodeRemainingLength(ByteBuf buf){
//        int remainingLength = 0;
//        int multiplier = 1;
//        short digit;
//        int loops = 0;
//        do {
//            // 读取一个字节
//            digit = buf.readUnsignedByte();
//            // 提取低7位并计算实际值
//            remainingLength += (digit & 127) * multiplier;
//            // 更新乘数，用于多字节情况
//            multiplier *= 128;
//            loops++;
//        } while ((digit & 128) != 0 && loops < 4);
//
//        return remainingLength;
//    }

private int decodeRemainingLength(ByteBuf in) {
    int multiplier = 1;
    int value = 0;
    byte encodedByte;
    do {
        encodedByte = in.readByte();
        value += (encodedByte & 127) * multiplier;
        multiplier *= 128;
    } while ((encodedByte & 128)!= 0);
    return value;
}

}

